﻿namespace 组合模式
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            //组合模式是一众结构形设计模式，他允许你将对象组合成树形结构来表示“整体-部分”层次结构。组合模式可以使客户端以一致的方式处理单个对象和对象集合，从而简化了客户端代码。
            //组合模式通常由一个抽象组件（Component）类和两个派生类-叶子组件（Leaf）和容器组件（Composite）组成。组合模式的核心思想是：将对象组合成树形结构来表示整体-部分的层次结构，并对外提供统一的访问方式。
            //在组合模式中，抽象组件是组合所有组件的基类，他声明了一些公共的操作，如添加，上出，获取子节点等，叶子组件表述树形结构中的叶子节点，他没有子节点，提供基本的操作，容器组件表示树形结构中的容器节点，他包含子节点，可以实现抽象组件中的所有操作。在容器组件中，可以通过递归调用子节点的方法，实现对整个树形结构的遍历。

            //真实世界类比：大部分国家的军队都采用层次结构管理。每个部队包括几个师，师由旅构成，旅由团构成，团可以继续划分为排。最后，每个排由一队队实实在在的士兵组成。军事命令由最高层下达，通过每个层级传递，直到每位士兵都知道自己该服从的命令。
            Product apple = new Item("apple", 1.2m);
            Product banana = new Item("Banana", 0.8m);
            Product melon = new Item("Melon", 3.5m);
            Product fruitBasket = new ProductComposite("Fruit Basket");
            fruitBasket.AddProducts(apple);
            fruitBasket.AddProducts(banana);
            fruitBasket.AddProducts(melon);

            Product mixedBasket = new ProductComposite("Mixed Basket");
            mixedBasket.AddProducts(fruitBasket);
            mixedBasket.AddProducts(new Item("Juice", 2.0m));

            decimal totalPrice = mixedBasket.GetPrice();
            Console.WriteLine("Total price:" + totalPrice);
        }
    }

    //假设有一个电子商务网站，其中有两类产品，一种是商品，另一种是商品组合。商品组合可以包含一到多个商品或其他商品组合，而商品是不能包含商品或其他商品组合的。现在我们需要设计一个类来表示这些产品并能够计算他们的价格。

    //首先我们定义一个抽象的产品类Product
    //其中包含了两个属性，名称和价格，以及一个抽象的方法GetProce（）；用以计算该产品的价格。

    //这种在抽象基类中定义所有行为，子类部分实现的方式称为透明式的组合模式
    public abstract class Product
    {
        protected string name;
        protected decimal price;

        protected Product(string name, decimal price)
        {
            this.name = name;
            this.price = price;
        }

        public abstract decimal GetPrice();

        public abstract void AddProducts(Product product);
    }

    //item类重写GetPrice（）方法，直接返回自己的价格。
    public class Item : Product
    {
        public Item(string name, decimal price) : base(name, price)
        {
        }

        public override decimal GetPrice()
        {
            return price;
        }

        public override void AddProducts(Product product)
        {
            throw new NotImplementedException();
        }
    }

    //ProductComposite类中包含了一个列表，用于存储包含的产品，同时重写GetPrice（）方法，用于计算并获取该商品组合的价格
    public class ProductComposite : Product
    {
        private List<Product> products = new List<Product>();

        public ProductComposite(string name) : base(name, 0)
        {
        }

        public override void AddProducts(Product product)
        {
            products.Add(product);
        }

        //递归计算该商品组合下所有商品的价格总和
        public override decimal GetPrice()
        {
            decimal totalProice = 0;
            foreach (Product product in products)
            {
                totalProice += product.GetPrice();
            }
            return totalProice;
        }
    }
}